package controlador;

import vista.MenuPrincipal;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;

import modelo.*;

public class ControladorMenuPrincipal implements ActionListener {

	private MenuPrincipal menu;
	private Liga liga;
	
	/*
	 * Acciones ejecutadas
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getActionCommand().equalsIgnoreCase("MenuRegistrar Arbitro")) {
			menu.MostrarPanelArbitro();
			menu.OcultarPanelEquipo();
		}
		if(e.getActionCommand().equalsIgnoreCase("BtnLimpiar Arbitro")) {
			menu.blanquearCamposArbitro();
		}
		if(e.getActionCommand().equalsIgnoreCase("BtnRegistrar Arbitro")) {
			this.ValidarRegistrarArbitro();
		}
		if(e.getActionCommand().equalsIgnoreCase("BtnSalir Arbitro")) {
			menu.OcultarPanelArbitro();
			menu.blanquearCamposArbitro();
		}
		if(e.getActionCommand().equalsIgnoreCase("MenuRegistrar Equipo")) {
			menu.MostrarPanelEquipo();
			menu.OcultarPanelArbitro();
		}
		if(e.getActionCommand().equalsIgnoreCase("BtnLimpiar Equipo")) {
			menu.blanquearCamposEquipo();
		}
		if(e.getActionCommand().equalsIgnoreCase("BtnAgregar Equipo")) {
			this.ValidarRegistrarEquipo();
		}
		if(e.getActionCommand().equalsIgnoreCase("BtnSalir Equipo")) {
			menu.OcultarPanelEquipo();
			menu.blanquearCamposEquipo();
		}
		if(e.getActionCommand().equalsIgnoreCase("btnCargarJugadores")) {
			menu.MostrarJFileChooser();
		}
		if(e.getActionCommand().equalsIgnoreCase("MenuSalir")) {
			menu.Salir();
		}
		if(e.getActionCommand().equalsIgnoreCase("MenuGenerar Partido")) {
			menu.OcultarPanelArbitro();
			menu.OcultarPanelEquipo();
			this.ValidarGenerarPartidos();
		}
		if(e.getActionCommand().equalsIgnoreCase("BtnGenerar Partido")) {
			this.GenerarPartido();
		}
		if(e.getActionCommand().equalsIgnoreCase("MenuTabla de Resultados")) {
			this.MostrarTabladeResultados();
		}
		if(e.getActionCommand().equalsIgnoreCase("MenuConsultar Calendario")) {
			this.MostrarCalendariodeJuegos();
		}
	}


	public ControladorMenuPrincipal() {
		super();
		liga = new Liga();
		menu = new MenuPrincipal();
		menu.agregarListener(this);
		menu.setLocationRelativeTo(null);
		menu.setVisible(true);
		menu.OcultarPanelArbitro();
		menu.OcultarPanelEquipo();
		menu.OcultarpanelFecha();
	}
	
	/*
	 * Funcion que registra el arbitro
	 */
	private void RegistrarArbitro() {
		try {
			String cedula, nombre, apellido, fecha_n;
			cedula = menu.getTxtArCedula();
			nombre = menu.getTxtArNombre();
			apellido = menu.getTxtArApellido();
			fecha_n = menu.getTxtArFecha();
			Arbitro arb = new Arbitro(cedula,nombre,apellido,fecha_n);
			liga.AnadirArbitro(arb);
			menu.blanquearCamposArbitro();
			menu.mostrarMensaje("El Arbitro " + nombre + " se ha anadido correctamente");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * Funcion que registra el equipo
	 */
	private void RegistrarEquipo() {
		try {
			String codigo, nombre_eq, estadio, ciudad, ano;
			codigo = menu.getTxtEqCodigo();
			nombre_eq = menu.getTxtEqNombre();
			estadio = menu.getTxtEqEstadio();
			ciudad = menu.getTxtEqCiudad();
			ano = menu.getTxtEqAno();
			Equipo equi = new Equipo(codigo,nombre_eq,ano,ciudad,estadio);
			menu.blanquearCamposEquipo();
			File arch = menu.getArcJugadores();
			menu.limpiarArchivoJugadores();

			//Se instancia el lector de archivos
			BufferedReader lector = new BufferedReader(new FileReader(arch));
			//Arreglo de jugadores
			ArrayList<Jugador> jugadores = new ArrayList<Jugador>();

			/*
			 * Mientras haya datos para leer del jugador, se cargan datos
			 */
			while(lector.ready()) {
				String cedula = lector.readLine();
				String nombre = lector.readLine();
				String apellido = lector.readLine();
				String fecha_n = lector.readLine();
				String posicion = lector.readLine();
				int carr = Integer.parseInt(lector.readLine());
				int cuad = Integer.parseInt(lector.readLine());
				jugadores.add(new Jugador(cedula,nombre,apellido,fecha_n,posicion,carr,cuad));
			}
			equi.setJugadores(jugadores);
			liga.AnadirEquipo(equi);
			menu.mostrarMensaje("Se ha añadido el equipo " + equi.getNombre() + " correctamente con " + jugadores.size() + " jugadores.");
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * Función que genera los partidos, los genera aleatoriamente, y dinamicamente,
	 * Primero genera los pares de juegos posibles, luego, va agarrando par por par, y comparando
	 * si ese par de equipos puede jugar ese dia, si no hay mas combinaciones posibles para ese dia,
	 * añade un dia mas a la cantidad de fechas posibles y empieza con las combinaciones el siguiente dia
	 */
	public void GenerarPartido() {
		if(menu.getTxtFechaInicial().matches("[0-3][0-9]/[01][0-9]/[12][09][0-9][0-9]"))
			{
				liga.GenerarPares();
				String f_i[] = menu.getTxtFechaInicial().split("/");
				menu.blanquearCampoFechaInic();
				Calendar fch = Calendar.getInstance();
				fch.set(Integer.parseInt(f_i[2]), Integer.parseInt(f_i[1])-1, Integer.parseInt(f_i[0]));
				/*
				 * Se crea el arreglo de nombres de los equipos para inicializar los 
				 * contadores de juegos
				 */
				ArrayList<String> nom = new ArrayList<String>();
				for(int i=0; i<liga.CantidadEquipos(); i++) {
					nom.add(liga.ObtenerEquipo(i).getNombre());
				}
					
				int codigo = 0;
				liga.InicializarContadoresJuegos(nom);
				int cant_fechas = liga.CantidadFechas();
				//Ciclo para la cantidad de dias que habra juego
				for(int i=0; i<cant_fechas; i++) {
					//Set para guardar los equipos que han jugado por dia
					Set<String> eq = new HashSet<String>();
					Set<String> ump = new HashSet<String>();
					/*
					 * Se compara que el dia no sea lunes, si el dia es lunes
					 * se decrementa el control del ciclo en 1
					 * Si el dia no es lunes se entra en el ciclo para
					 * realizar los juegos de ese dia
					 */
					int cont_partidos = 0;
					if(liga.getCantidadPares()==0)
						break;
					if(fch.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY)
							i--;
					else
						for(int j=0; j<liga.PartidosPorDia(); j++) { //Ciclo de juegos por dia
							Equipo e1 = null;
							Equipo e2 = null;
							if(liga.getCantidadPares()==0)
								break;
							boolean ver1, ver2;
							Equipo par[] = null;
							int cont_while = 0;
							do {
								par = liga.getParAleatorio();
								e1 = par[0];
								e2 = par[1];
								if(eq.contains(e1.getNombre()))
									ver1 = true;
								else
									ver1 = false;
								if(eq.contains(e2.getNombre()))
									ver2 = true;
								else
									ver2 = false;
								cont_while++;
								if(cont_partidos >= 1 && cont_while > 25) {
									cant_fechas++;
									par = null;
									break;
								}
							}while(ver1 || ver2);
							if(par != null)
							{
								eq.add(e1.getNombre());
								eq.add(e2.getNombre());
								liga.EliminarPar(par);
								cont_partidos++;
							}
							else
								break;
							Arbitro arb = new Arbitro();
							do {
								arb = liga.ObtenerArbitroAleatorio();
							}while(ump.contains(arb.getNombre().toLowerCase()));
							ump.add(arb.getNombre().toLowerCase());
							Calendar fch_clon = (Calendar)fch.clone();
							codigo++;
							liga.GenerarPartido(codigo,e1, e2, arb, fch_clon);
						}
					fch.add(Calendar.DAY_OF_MONTH, 1);
				}
				menu.mostrarMensaje("Se han generado " + liga.cantidadPartidos() + " partidos correctamente.");
				menu.OcultarpanelFecha();
			}
			else
				menu.mostrarMensaje("Campo Invalido\nDebe ser de la forma DD/MM/AAAA");
	}
	
	/*
	 * Función que valida que las condiciones necesarias para generar los partidos se cumplan
	 * Y que si ya se han generado partidos, no puedan generarse mas partidos
	 */
	public void ValidarGenerarPartidos() {
		if(liga.CantidadArbitros() < liga.PartidosPorDia())
			menu.mostrarMensaje("Arbitros Insuficientes\nDebe haber " + liga.PartidosPorDia() + " arbitros.\n" +
					"Actualmente hay " + liga.CantidadArbitros());
		else
			if(liga.CantidadArbitros()==0 || liga.CantidadEquipos()==0)
				menu.mostrarMensaje("Primero debe registrar Arbitros y Equipos");
			else
				if(liga.CantidadEquipos()%2 != 0)
					menu.mostrarMensaje("La cantidad de equipos debe ser par");
				else
					if(liga.cantidadPartidos()>0)
						menu.mostrarMensaje("Ya se han generado partidos.");
					else {
						menu.MostrarPanelFecha();
						menu.setTxtFechaInic("DD/MM/AAAA");
					}
	}
	
	/*
	 * Funcioón que valida el registro de los arbitros, sólo pueden registrarse arbitros
	 * si ningún campo esta vacío y si la fecha esta escrita en el formato correcto
	 */
	public void ValidarRegistrarArbitro() {
		if(menu.getTxtArCedula().isEmpty() || menu.getTxtArNombre().isEmpty() || menu.getTxtArApellido().isEmpty()
			|| menu.getTxtArFecha().isEmpty())
			menu.mostrarMensaje("Ningún campo debe quedar vacío");
		else
			if(menu.getTxtArFecha().matches("[0-3][0-9]/[01][0-9]/[12][09][0-9][0-9]"))
				this.RegistrarArbitro();
			else
				menu.mostrarMensaje("Valor de Fecha Inválido");
	}
	
	/*
	 * Funcion que valida que se pueda registrar el equipo
	 * Solo puede registrarse un equipo si ningun campo esta en blanco, y
	 * si se ha seleccionado ya un archivo de jugadores válido
	 */
	public void ValidarRegistrarEquipo() {
		if(menu.getTxtEqCodigo().isEmpty() || menu.getTxtEqNombre().isEmpty() || menu.getTxtEqCiudad().isEmpty()
				|| menu.getTxtEqEstadio().isEmpty() || menu.getTxtEqAno().isEmpty()) {
			menu.mostrarMensaje("Ningún campo debe estar vacío.");
		}
		else
			if(menu.getArcJugadores() == null) {
				menu.mostrarMensaje("Primero debe seleccionar un archivo de jugadores");
			}
			else
				this.RegistrarEquipo();
	}
	
	/*
	 * Metodo que muestra la tabla de resultados de la temporada
	 */
	public void MostrarTabladeResultados() {
		if(liga.cantidadPartidos() == 0)
			menu.mostrarMensaje("Primero debe generar los partidos.");
		else {
			ControladorVentanaTablaPosiciones tabla = new ControladorVentanaTablaPosiciones(this.liga);
		}
	}
	
	/*
	 * Metodo que muestra el calendario de juegos de la temporada
	 */
	public void MostrarCalendariodeJuegos() {
		if(liga.cantidadPartidos() == 0)
			menu.mostrarMensaje("Primero debe generar los partidos.");
		else {
			ControladorVentanaCalendario calendario = new ControladorVentanaCalendario(this.liga);
		}	
	}
}
